package com.CMUBiS.PageControllers;

import java.util.*;

import javax.servlet.http.HttpServletRequest;

import com.CMUBiS.Data.Error;
import com.CMUBiS.Data.GlobalVars;
import com.CMUBiS.util.Category;
import com.CMUBiS.util.CheckInputs;
import com.CMUBiS.util.Item;
import com.CMUBiS.util.StopWatch;

/**
 * This class processes the data for the browse category servlet
 * 
 * @author Andy (andrewtu@cmu.edu, turner.andy@gmail.com)
 * @version 0.1
 * @since 0.1
 * @date 04/05/2011
 */

public class BrowseCategoryController extends PageController{
	// Variables passed in the request
	private int userID = 0;
	private String authToken = null;
	private int categoryID = 0;
	private int pageNo = 0;
	private int itemsPP = 0;
	
	// Structures to hold the DB data
	private Category parentCategory = null;
	private ArrayList<Category> subCategories = null;
	private ArrayList<Item> items = null;
	private String previousPageURL = "< Previous Page";
	private String nextPageURL = "Next Page >";
	
	// Structures to hold the parsed page data
	private String parentCategoryURL = null;
	private String[] subCategoryURLs = null;
	private String[] itemURLs = null;

	/**
	 * This method checks the page for any input errors that may have come from Client generator error
	 * These would need to be check in real life to stop users attempting to hack and mess with things
	 * The browse page does not need a username and authToken to use, so they are not strictly checked
	 * by the page
	 * 
	 * @param request
	 * @author Andy (andrewtu@cmu.edu, turner.andy@gmail.com)
	 */
	public void checkInputs(HttpServletRequest request){
		StopWatch timer;
		if(GlobalVars.collectStats){
			timer = new StopWatch();
			timer.start();
		}
		
		if(request != null){
			super.checkInputs(request);
			
			// Get the userID (if exists), we will pass it along to the next pages
			try{
				this.userID = CheckInputs.checkUserID(request);
			}
			catch(Error e){
				if(!errors.contains(e))
					errors.add(e);
			}
			
			// Get the authToken (if exists), we will pass it along to the next pages
			try{
				this.authToken = CheckInputs.checkAuthToken(request);
			}
			catch(Error e){
				if(!errors.contains(e))
					errors.add(e);
			}
			
			// Get the category ID. If there isn't one we just start at the root category
			try{
				this.categoryID = CheckInputs.checkCategoryID(request);
			}
			catch(Error e){
				if(!errors.contains(e))
					errors.add(e);
				this.categoryID = 0;
			}
			
			// Get the page number. If there isn't one we'll just start at page zero
			try{
				this.pageNo = CheckInputs.checkPageNumber(request);
			}
			catch(Error e){
				if(!errors.contains(e))
					errors.add(e);
				this.pageNo = 0;
			}
			
			// Get the number of items per page. If there isn't one defined we'll use the default of 25
			try{
				this.itemsPP = CheckInputs.checkItemsPerPage(request);
			}
			catch(Error e){
				if(!errors.contains(e))
					errors.add(e);
				this.itemsPP = 25;
			}
		}
		
		// Calculate how long that took
		if(GlobalVars.collectStats){
			timer.stop();
			this.totalGetParamTime += timer.getTimeTaken();
		}
	}
	
	/**
	 * This method get the data needed for the HTML4 page from the database
	 * 
	 * @author Andy (andrewtu@cmu.edu, turner.andy@gmail.com)
	 */
	public void getHTML4Data(){
		/*
		 * Get all of the info needed from the database
		 */
		StopWatch timer;
		if(GlobalVars.collectStats){
			timer = new StopWatch();
			timer.start();
		}
		
		// Get the current parent category
		try{
			parentCategory = GlobalVars.db.getCategory(this.categoryID);
		}
		catch(Exception e){
			errors.add(new Error("BrowseCategoryControl: getHTML4Data: Could not read from data base when getting parent category!", e));
		}
		
		// Get the parent category's sub-categories
		try{
			subCategories = GlobalVars.db.getCategories(this.categoryID);
		}
		catch(Exception e){
			errors.add(new Error("BrowseCategoryControl: getHTML4Data: Could not read from data base when getting the sub categories", e));
		}
		
		// Get all of the items in the category
		try{
			items = GlobalVars.db.getCategoryItems(this.categoryID, this.pageNo, this.itemsPP);
		}
		catch(Exception e){
				errors.add(new Error("BrowseCategoryControl: getHTML4Data: Could not read from data base when getting the items", e));
		}
		
		// Calculate how long that took
		if(GlobalVars.collectStats){
			timer.stop();
			this.totalDBtime += timer.getTimeTaken();
		}
	}
	
	/**
	 * This method processes all of the data that was read from the database such that it is ready to be printed
	 * on to the page. We try to do as much of the page logic here as possible
	 * 
	 * @author Andy (andrewtu@cmu.edu, turner.andy@gmail.com)
	 */
	public void processHTML4(){
		/*
		 * Process the data and make the URLs to be displayed
		 */
		StopWatch timer;
		if(GlobalVars.collectStats){
			timer = new StopWatch();
			timer.start();
		}
		
		// Make the parent category URL links
		if(parentCategory !=null)
			this.parentCategoryURL = "<a href=\"./browsecategory?"
					+ (this.hasUserID() ? "userID=" + this.getUserIDString() +"&": "")
					+ (this.hasAuthToken() ? "authToken=" + this.getAuthTokenString() +"&": "")
					+ "pageNo=" + this.pageNo +"&"
					+ "itemsPP=" + this.itemsPP +"&"
					+ "categoryID=" + this.getCategoryID()
					+ "\">" + parentCategory.getName() + "</a>";
		else this.parentCategoryURL = "";
		
		// Make the URL links for the sub-categories
		if(subCategories != null){
			int subCategoriesSize = subCategories.size();
			
			this.subCategoryURLs = new String[subCategoriesSize];
			for(int i=0; i < subCategoriesSize; i++){
				this.subCategoryURLs[i] = "<label for\"catlink" + i + "\"><a href=\"./browsecategory?"
					+ (this.hasUserID() ? "userID=" + this.getUserIDString() +"&": "")
					+ (this.hasAuthToken() ? "authToken=" + this.getAuthTokenString() +"&": "")
					+ "pageNo=" + this.pageNo +"&"
					+ "itemsPP=" + this.itemsPP +"&"
					+ "categoryID=" + subCategories.get(i).getCategoryID()
					+ "\">" + subCategories.get(i).getName() + "</a></label>";
			}
		}
		else this.subCategoryURLs = new String[0];
		
		// Make the URL links for the items
		if(this.items != null){
			int itemsSize = this.items.size();
			
			this.itemURLs = new String[itemsSize];
			for(int i=0; i < itemsSize; i++){
				this.itemURLs[i] = "<a href=\"./viewitem?"
					+ (this.hasUserID() ? "userID=" + this.getUserIDString() +"&": "")
					+ (this.hasAuthToken() ? "authToken=" + this.getAuthTokenString() +"&": "")
					+ "itemID=" + items.get(i).getID()
					+ "\">" + items.get(i).getName() + "</a>";
			}
		}
		else this.itemURLs = new String[0];
		
		// Make the URLs for the previous and next page
		// If we are further than page zero we can go backwards
		if(this.pageNo>0)
			this.previousPageURL = "<a href=\"./browsecategory?"
				+ (this.hasUserID() ? "userID=" + this.getUserIDString() +"&": "")
				+ (this.hasAuthToken() ? "authToken=" + this.getAuthTokenString() +"&": "")
				+ "pageNo=" + (this.pageNo-1) +"&"
				+ "itemsPP=" + this.itemsPP +"&"
				+ "categoryID=" + this.getCategoryID()
				+ "\">< Previous Page</a>";
		
		// If there are less items remaining than we want to display then there are no more pages
		if(this.items != null && this.items.size() >= this.itemsPP)
			this.nextPageURL = "<a href=\"./browsecategory?"
				+ (this.hasUserID() ? "userID=" + this.getUserIDString() +"&": "")
				+ (this.hasAuthToken() ? "&authToken=" + this.getAuthTokenString() +"&": "")
				+ "pageNo=" + (this.pageNo+1) +"&"
				+ "itemsPP=" + this.itemsPP +"&"
				+ "categoryID=" + this.getCategoryID()
				+ "\">Next Page ></a>";
		
		
		// Calculate how long that took
		if(GlobalVars.collectStats){
			timer.stop();
			this.totalProcessingTime += timer.getTimeTaken();
		}
	}
	
	/**
	 * Gets the HTML5 data from the database
	 * 
	 * @author Andy (andrewtu@cmu.edu, turner.andy@gmail.com)
	 */
	public void getHTML5Data(){
		StopWatch timer;
		if(GlobalVars.collectStats){
			timer = new StopWatch();
			timer.start();
		}
		
		// Calculate how long that took
		if(GlobalVars.collectStats){
			timer.stop();
			this.totalDBtime += timer.getTimeTaken();
		}
	}
	
	/**
	 * Processes the HTML5 data that is needed to create the page
	 * 
	 * @author Andy (andrewtu@cmu.edu, turner.andy@gmail.com)
	 */
	public void processHTML5(){
		StopWatch timer;
		if(GlobalVars.collectStats){
			timer = new StopWatch();
			timer.start();
		}
		
		// Calculate how long that took
		if(GlobalVars.collectStats){
			timer.stop();
			this.totalProcessingTime += timer.getTimeTaken();
		}
	}
	
	/**
	 * Returns the current userID as a String
	 * 
	 * @return String the userID
	 * @author Andy (andrewtu@cmu.edu, turner.andy@gmail.com)
	 */
	public String getUserIDString(){
		return Integer.toString(this.userID);
	}
	
	/**
	 * Returns if a userID was sent to the page
	 * 
	 * @return boolean if a userID was passed and correct
	 * @author Andy (andrewtu@cmu.edu, turner.andy@gmail.com)
	 */
	public Boolean hasUserID(){
		return this.userID > 0;
	}
	
	/**
	 * Returns the authToken sent to the page
	 * 
	 * @return string the authToken
	 * @author Andy (andrewtu@cmu.edu, turner.andy@gmail.com)
	 */
	public String getAuthTokenString(){
		return this.authToken;
	}
	
	/**
	 * Returns if a authToken was sent to the page
	 * 
	 * @return boolean if the authToken was present and correct
	 * @author Andy (andrewtu@cmu.edu, turner.andy@gmail.com)
	 */
	public Boolean hasAuthToken(){
		return !(this.authToken == null || this.authToken.equals(EMPTY));
	}
	
	/**
	 * Returns the categoryID sent to the page
	 * 
	 * @return int the categoryID
	 * @author Andy (andrewtu@cmu.edu, turner.andy@gmail.com)
	 */
	public int getCategoryID(){
		return this.categoryID;
	}
	
	/**
	 * Returns the URL string for the link back to the parent category
	 * 
	 * @return String the parent category URL
	 * @author Andy (andrewtu@cmu.edu, turner.andy@gmail.com)
	 */
	public String getParentCategoryURL(){
		return this.parentCategoryURL;
	}
	
	/**
	 * Returns the URLs for the links to the sub-categories
	 * 
	 * @return String[] the sub caregory URLs
	 * @author Andy (andrewtu@cmu.edu, turner.andy@gmail.com)
	 */
	public String[] getSubCategoryURLs(){
		return this.subCategoryURLs;
	}
	
	/**
	 * Returns the URLs for the links to the items returned by the search
	 * 
	 * @return String[] the URLs to the items thumbnails
	 * @author Andy (andrewtu@cmu.edu, turner.andy@gmail.com)
	 */
	public String[] getItemURLs(){
		return this.itemURLs;
	}
	
	/**
	 * Returns the page number that the user is currently viewing
	 * 
	 * @return int the current page number we are viewing
	 * @author Andy (andrewtu@cmu.edu, turner.andy@gmail.com)
	 */
	public int getPageNo(){
		return this.pageNo;
	}
	
	/**
	 * Returns the URL to go to the previous page
	 * 
	 * @return String the URL to go to the previous page
	 * @author Andy (andrewtu@cmu.edu, turner.andy@gmail.com)
	 */
	public String getPreviousPageURL(){
		return this.previousPageURL;
	}
	
	/**
	 * Returns the URL to go to the next page
	 * 
	 * @return String the URL to the next page
	 * @author Andy (andrewtu@cmu.edu, turner.andy@gmail.com)
	 */
	public String getNextPageURL(){
		return this.nextPageURL;
	}
	
	/**
	 * Returns the list of items
	 * 
	 * @return ArrayList<Item> the list of items
	 * @author Andy (andrewtu@cmu.edu, turner.andy@gmail.com)
	 */
	public ArrayList<Item> getItems(){
		return this.items;
	}
}
